package com.heo.client.app;

import java.util.Date;

import javax.swing.JTextArea;

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

import com.heo.protocol.DeviceProtocolDecoder;
import com.heo.protocol.DeviceProtocolEncoder;
import com.heo.pub.ClientConfig;
import com.heo.server.SocketServerBootstrap;
import com.heo.util.TimeHelper;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;

public class AppClientBootstrap implements Runnable
{

  private Logger log = Logger.getLogger(this.getClass());

  private int port;
  private String host;
  private static String lineWrap = "\r\n";
  private DeviceWindow window;

  private int index = 0;

  public AppClientBootstrap(String host, int port, int index, DeviceWindow window)
  {
    this.index = index;
    this.host = host;
    this.port = port;
    this.window = window;
  }

  public AppClientBootstrap(String host, int port)
  {
    this.host = host;
    this.port = port;
  }

  @Override
  public void run()
  {
    connect(this.host, this.port);
  }

  // 建立连接
  private void connect(String host, int port)
  {
    EventLoopGroup workerGroup = new NioEventLoopGroup();
    try
    {
      Bootstrap bootstrap = new Bootstrap();
      bootstrap.channel(NioSocketChannel.class);
      bootstrap.option(ChannelOption.TCP_NODELAY, true);
      bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
      bootstrap.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, ClientConfig.CONNECT_TIME);
      bootstrap.group(workerGroup);

      bootstrap.handler(new ChannelInitializer<SocketChannel>()
      {
        @Override
        protected void initChannel(SocketChannel socketChannel) throws Exception
        {
          // socketChannel.pipeline().addLast(new FixedLengthFrameDecoder(10));
          socketChannel.pipeline().addLast(new DeviceProtocolEncoder());
          socketChannel.pipeline().addLast(new DeviceProtocolDecoder());
          socketChannel.pipeline().addLast(new IdleStateHandler(ClientConfig.READ_IDLE_TIME, ClientConfig.WRITE_IDLE_TIME, ClientConfig.ALL_IDLE_TIME));
          socketChannel.pipeline().addLast(new AppClientHandler(index, window));
        }
      });

      ChannelFuture future = bootstrap.connect(host, port).sync();
      future.addListener(new ChannelFutureListener()
      {
        @Override
        public void operationComplete(ChannelFuture future) throws Exception
        {
          if (future.isSuccess())
          {
            log.info("[client]连接创建成功。");
          }
          else
          {
            log.info("[client]连接创建失败。");
          }
        }
      });
      future.channel().closeFuture().sync();
    }
    catch (Exception e)
    {
      log.error("[client]与服务器连接异常： " + e.getMessage());
      log.error(e.getMessage(), e);
      window.getConsoleArea().append(now() + "[client][" + index + "]与服务器连接异常： " + e.getMessage() + lineWrap);
      reConnect(host, port);
    }
    finally
    {
      workerGroup.shutdownGracefully();
    }
  }

  private String now()
  {
    return TimeHelper.dateTimeToStr(new Date()) + " - ";
  }

  /**
   * 断线重连
   * 
   * @param host
   * @param port
   */
  private void reConnect(String host, int port)
  {
    try
    {
      log.error("[client]与服务器连接已断开， " + ClientConfig.RECONNECT_TIME + "毫秒后重新连接。");
      window.getConsoleArea().append(now() + "[client][" + index + "]与服务器连接已断开， " + ClientConfig.RECONNECT_TIME + "毫秒后重新连接。" + lineWrap);
      Thread.sleep(ClientConfig.RECONNECT_TIME);
      connect(host, port);
    }
    catch (Exception e)
    {
      log.error(e.getMessage(), e);
    }
  }

  public static void main(String[] args)
  {
    PropertyConfigurator.configure(SocketServerBootstrap.class.getResource("/").getPath() + "/com/heo/config/log4j.properties");
    for (int i = 0; i < 5; i++)
    {
      AppClientBootstrap client = new AppClientBootstrap(ClientConfig.SERVER_IP, ClientConfig.PORT, i, null);
      Thread thread1 = new Thread(client);
      thread1.start();
      try
      {
        thread1.sleep(3000);
      }
      catch (InterruptedException e)
      {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }
  }

}